#!/usr/bin/env python

"""
The Main text area for TUI module.
"""

# Author: Likayo Lee

__all__ = {"MainText"}

import curses

class MainText:
    """
    The main text area.
    """
    # Conceptually, it is inherited from built-in class curses.window, which is
    #   not allowed by Python. As an alternative solution, the __setattr__ and 
    #   __getattr__ functions are overrid to imitate C++ "public" inheritance.
    # See http://code.activestate.com/recipes/52295/ for more details.
    # This method has a problem: I can no longer assign to any attrs. I hacked
    #   this problem by removing __setattr__  method. In this way, this 
    #   inheritance is slightly different from C++ "public", because I can't 
    #   write any public attr of "curses.window" object. In this case that's 
    #   not a problem.

    MAX_LINE = 1000     # the max number of lines to show.

    def __init__(self, init_h, init_w):
        """
        Initializes the text area.

        The text area is fixed to the leftmost point of screen.

        Args:
            init_h, init_w: the initial size of text area.
        """
        self.__dict__['pad'] = curses.newpad(self.MAX_LINE, init_w)
            # not self.pad, to avoid triggering __setattr__
        self._height          = init_h
        self._width           = init_w
        self._content         = ""
        self._content_type    = "plain"
        self._encoding        = None
        self.current_pos      = 0   # line No. of the top line
        self.lines            = 0
        self.refresh_cmd     = ""

    def replace_content(self, content, content_type, refresh_cmd, encoding):
        """
        Replaces the content of text area with new content.

        The content will be printed on the text area immediately.

        Args:
            content: the new content. *NOT* encoded
            content_type: the type of content.
            refresh_cmd: the command to be executed when refreshing.
            encoding: 
        """
        assert content_type in {"plain", "weibo", "user", "comment", "error"}
        self._content = content
        self._content_type = content_type
        self._encoding = encoding
        self.lines = self._paint_content()
        self.current_pos = 0
        self.refresh_cmd = refresh_cmd

    # override
    def resize(self, nlines, ncols):
        self._height = nlines
        self._width = ncols
        retval = self.pad.resize(self.MAX_LINE, ncols)
        self.lines = self._paint_content()
        return retval

    # override
    def refresh(self):
        self.pad.refresh(  self.current_pos,   0,
                            0,                  0,  # leftmost of main screen
                            self._height-1,     self._width-1)
        return 

    def _paint_content(self):
        """
        Paint the current content.

        Returns:
            The number of lines of painted content..
        """
        self.pad.touchwin()
        self.pad.erase()
        if self._content_type == "weibo":
            return self._paint_weibos()
        elif self._content_type == "user":
            assert False
        elif self._content_type == "comment":
            return self._paint_comments()
        else: #if self._content_type == "plain": or error
            try:
                self.pad.addstr(0,0,self._content.encode(self._encoding))
            except curses.error:    # ignore "out of range"
                pass
            y, x = self.pad.getyx()
            return y + 1

    def _paint_weibos(self):
        """
        Paint the content of weibo(s).

        Format: {1: {xxx}, 2: {yyy}, }
        """
        self.pad.erase()
        self.pad.move(0,0)
        for i, wb in self._content.iteritems():
            username = "#%d @%s" % (i, wb["user"]["name"].encode(self._encoding))
            try:
                self.pad.addstr(username, curses.COLOR_CYAN | curses.A_BOLD)
            except curses.error:    # ignore "out of range"
                pass
            content = (": %s\n\tTime: %s\n\tComments: %d\n\n"
                         % (wb["text"].encode(self._encoding),
                            wb["created_at"].encode(self._encoding),
                            wb["comments_count"],))
            try:
                self.pad.addstr(content)
            except curses.error:    # ignore "out of range"
                pass
        y, x = self.pad.getyx()
        return y + 1

    def _paint_comments(self):
        """
        Paint the content of comment(s).
        """
        self.pad.erase()
        self.pad.move(0,0)
        for i, comment in self._content.iteritems():
            username = "#%d @%s" % (i, comment["user"]["name"].encode(self._encoding))
            try:
                self.pad.addstr(username, curses.COLOR_CYAN | curses.A_BOLD)
            except curses.error:    # ignore "out of range"
                pass
            content = (": %s\n\tTime: %s\n\n"
                         % (comment["text"].encode(self._encoding), 
                            comment["created_at"].encode(self._encoding),))
            try:
                self.pad.addstr(content)
            except curses.error:    # ignore "out of range"
                pass
        y, x = self.pad.getyx()
        return y + 1

    def __getattr__(self, attr):
        return getattr(self.pad, attr)
    # def __setattr__(self, attr, value):
    #     return setattr(self.pad, attr, value) 